<script>
  //导入所有节点组件
  import Approval from '@/views/flow/process/nodes/ApprovalNode.vue'
  import Cc from '@/views/flow/process/nodes/CcNode.vue'
  import Empty from '@/views/flow/process/nodes/EmptyNode.vue'
  import Root from '@/views/flow/process/nodes/RootNode.vue'
  import Node from '@/views/flow/process/nodes/Node.vue'

  import DefaultProps from "./DefaultNodeProps"

  export default {
    name: "ProcessTree",
    components: {
      Node,
      Root,
      Approval,
      Cc,
      Empty
    },
    data() {
      return {
        valid: true
      }
    },
    computed: {
      nodeMap() {
        return this.$store.state.nodeMap;
      },
      dom() {
        return this.$store.state.design.process;
      }
    },
    render(h, ctx) {
      this.nodeMap.clear()
      let processTrees = this.getDomTree(h, this.dom)
      //插入末端节点
      processTrees.push(h('div', {
        style: {
          'text-align': 'center'
        }
      }, [
        h('div', {
          class: {
            'process-end': true
          },
          domProps: {
            innerHTML: '流程结束'
          }
        })
      ]))
      return h('div', {
        class: {
          '_root': true
        },
        ref: '_root'
      }, processTrees)
    },
    methods: {
      getDomTree(h, node) {
        this.toMapping(node);
        if (this.isPrimaryNode(node)) {
          //普通业务节点
          let childDoms = this.getDomTree(h, node.children)
          this.decodeAppendDom(h, node, childDoms)
          return [h('div', {
            'class': {
              'primary-node': true
            }
          }, childDoms)];
        } else {
          //遍历到了末端，无子节点
          return [];
        }
      },
      //解码渲染的时候插入dom到同级
      decodeAppendDom(h, node, dom, props = {}) {
        props.config = node
        dom.unshift(h(node.type.toLowerCase(), {
          props: props,
          ref: node.id,
          key: node.id,
          //定义事件，插入节点，删除节点，选中节点，复制/移动
          on: {
            insertNode: type => this.insertNode(type, node),
            delNode: () => this.delNode(node),
            selected: () => this.selectNode(node),
            copy: () => this.copyBranch(node),
            leftMove: () => this.branchMove(node, -1),
            rightMove: () => this.branchMove(node, 1)
          }
        }, []))
      },
      //id映射到map，用来向上遍历
      toMapping(node) {
        if (node && node.id) {
          //console.log("node=> " + node.id + " name:" + node.name + " type:" + node.type)
          this.nodeMap.set(node.id, node)
        }
      },
      branchMove(node, offset) {
        let parentNode = this.nodeMap.get(node.parentId)
        let index = parentNode.branchs.indexOf(node)
        let branch = parentNode.branchs[index + offset]
        parentNode.branchs[index + offset] = parentNode.branchs[index]
        parentNode.branchs[index] = branch
        this.$forceUpdate()
      },
      //判断是否为主要业务节点
      isPrimaryNode(node) {
        return node &&
          (node.type === 'ROOT' || node.type === 'APPROVAL' ||
            node.type === 'CC');
      },
      isBranchNode(node) {
        return node && (node.type === 'CONDITIONS' || node.type === 'CONCURRENTS');
      },
      isEmptyNode(node) {
        return node && (node.type === 'EMPTY')
      },
      //是分支节点
      isConditionNode(node) {
        return node.type === 'CONDITIONS';
      },
      //是分支节点
      isBranchSubNode(node) {
        return node && (node.type === 'CONDITION' || node.type === 'CONCURRENT');
      },
      isConcurrentNode(node) {
        return node.type === 'CONCURRENTS'
      },
      getRandomId() {
        return `node_${new Date().getTime().toString().substring(5)}${Math.round(Math.random()*9000+1000)}`
      },
      //选中一个节点
      selectNode(node) {
        this.$store.commit('selectedNode', node)
        this.$emit('selectedNode', node)
      },
      //处理节点插入逻辑
      insertNode(type, parentNode) {
        this.$refs['_root'].click()
        //缓存一下后面的节点
        let afterNode = parentNode.children
        //插入新节点
        parentNode.children = {
          id: this.getRandomId(),
          parentId: parentNode.id,
          props: {},
          type: type,
          weight:0
        }
        switch (type) {
          case 'APPROVAL':
            this.insertApprovalNode(parentNode, afterNode);
            break;
          case 'CC':
            this.insertCcNode(parentNode);
            break;
          default:
            break;
        }
        if (afterNode && afterNode.id) {
          afterNode.parentId = parentNode.children.id
        }
        this.$set(parentNode.children, 'children', afterNode)
        this.$forceUpdate()
        console.log(this.$store.state)
      },
      insertApprovalNode(parentNode) {
        this.$set(parentNode.children, "name", "审批人")
        this.$set(parentNode.children, "props", this.$deepCopy(DefaultProps.APPROVAL_PROPS))
      },
      insertCcNode(parentNode) {
        this.$set(parentNode.children, "name", "接收人")
        this.$set(parentNode.children, "props", this.$deepCopy(DefaultProps.CC_PROPS))
      },
      //删除当前节点
      delNode(node) {
        console.log("删除节点", node)
        //获取该节点的父节点
        let parentNode = this.nodeMap.get(node.parentId)
        if (parentNode) {
          if (node.children && node.children.id) {
            node.children.parentId = parentNode.id
          }
          parentNode.children = node.children
          this.$forceUpdate()
        } else {
          this.$message.warning("出现错误，找不到上级节点😥")
        }
      },
      validateProcess() {
        this.valid = true
        let err = []
        this.validate(err, this.dom)
        return err
      },
      validateNode(err, node) {
        if (this.$refs[node.id].validate) {
          this.valid = this.$refs[node.id].validate(err)
        }
      },
      //更新指定节点的dom
      nodeDomUpdate(node) {
        this.$refs[node.id].$forceUpdate()
      },
      //给定一个起始节点，遍历内部所有节点
      forEachNode(parent, node, callback) {
        if (this.isBranchNode(node)) {
          callback(parent, node)
          this.forEachNode(node, node.children, callback)
          node.branchs.map(branchNode => {
            callback(node, branchNode)
            this.forEachNode(branchNode, branchNode.children, callback)
          })
        } else if (this.isPrimaryNode(node) || this.isEmptyNode(node) || this.isBranchSubNode(node)) {
          callback(parent, node)
          this.forEachNode(node, node.children, callback)
        }
      },
      //校验所有节点设置
      validate(err, node) {
        if (this.isPrimaryNode(node)){
          this.validateNode(err, node)
          this.validate(err, node.children)
        }else if (this.isEmptyNode(node)){
          this.validate(err, node.children)
        }
      }
    }
  }
</script>

<style lang="scss" scoped>
  ._root {
    margin: 0 auto;
  }

  .process-end {
    width: 60px;
    margin: 0 auto;
    margin-bottom: 20px;
    border-radius: 15px;
    padding: 5px 10px;
    font-size: small;
    color: #747474;
    background-color: #f2f2f2;
    box-shadow: 0 0 10px 0 #bcbcbc;
  }

  .primary-node {
    display: flex;
    align-items: center;
    flex-direction: column;
  }

  .branch-node {
    display: flex;
    justify-content: center;
    /*border-top: 2px solid #cccccc;
   border-bottom: 2px solid #cccccc;*/
  }

  .branch-node-item {
    position: relative;
    display: flex;
    background: #f5f6f6;
    flex-direction: column;
    align-items: center;
    border-top: 2px solid #cccccc;
    border-bottom: 2px solid #cccccc;

    &:before {
      content: "";
      position: absolute;
      top: 0;
      left: calc(50% - 1px);
      margin: auto;
      width: 2px;
      height: 100%;
      background-color: #CACACA;
    }

    .line-top-left,
    .line-top-right,
    .line-bot-left,
    .line-bot-right {
      position: absolute;
      width: 50%;
      height: 4px;
      background-color: #f5f6f6;
    }

    .line-top-left {
      top: -2px;
      left: -1px;
    }

    .line-top-right {
      top: -2px;
      right: -1px;
    }

    .line-bot-left {
      bottom: -2px;
      left: -1px;
    }

    .line-bot-right {
      bottom: -2px;
      right: -1px;
    }
  }

  .add-branch-btn {
    position: absolute;
    width: 80px;

    .add-branch-btn-el {
      z-index: 999;
      position: absolute;
      top: -15px;
    }
  }

  .empty-node {
    display: flex;
    justify-content: center;
    flex-direction: column;
    align-items: center;
  }
</style>
